//
//  UITextInput+AD.swift
//  ADKit
//
//  Created by Adoma on 2023/6/16.
//

import RxSwift
import RxCocoa

public extension Notification.Name {
    static let textDidBeyondLimitNotification = Notification.Name.init(rawValue: "ADKit.UITextInput.textDidBeyondLimitNotification")
}

extension UITextInput {
    
    /// 文本限制的最大长度
    /// 为 nil 是表示不限制
    /// by ADKit
    public var textLimit: Int? {
        get {
            return observer?.limit
        }
        set {
            if let textLimit = newValue {
                observer = Observer(textInput: self, limit: textLimit)
            } else {
                observer = nil
            }
        }
    }
}

private var observerKey: UInt8 = 0
private var textSubjectKey: UInt8 = 0

extension UITextInput {
    
    fileprivate var observer: Observer? {
        get {
            objc_getAssociatedObject(self, &observerKey) as? Observer
        }
        set {
            objc_setAssociatedObject(self, &observerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

fileprivate protocol LimitLengthInput: UITextInput {
    var userInput: String? { get set }
    func checkUserInputFor(limit: Int)
}

extension UITextView: LimitLengthInput {
    
    fileprivate var userInput: String? {
        get {
            return self.text
        }
        set {
            self.text = newValue
        }
    }
}

extension UITextField: LimitLengthInput {
    
    fileprivate var userInput: String? {
        get {
            return self.text
        }
        set {
            self.text = newValue
            self.sendActions(for: .valueChanged)
        }
    }
}

extension LimitLengthInput  {
    
    func checkUserInputFor(limit: Int) {
        
        guard self.markedTextRange == nil else {
            return
        }

        let text = self.userInput
        userInput = text?.prefix(limit).toString

        NotificationCenter.default.post(name: .textDidBeyondLimitNotification, object: self)
        
    }
    
}

fileprivate final class Observer {
    
    weak var textInput: UITextInput?
    let limit: Int
    
    init(textInput: UITextInput, limit: Int) {
        
        self.textInput = textInput
        self.limit = limit
        checkUserInput()
        
        if textInput is UITextField {
            NotificationCenter.default
                .addObserver(self, selector: #selector(textDidChange(notification:)),
                             name: UITextField.textDidChangeNotification,
                             object: textInput)
        }
        else if textInput is UITextView {
            NotificationCenter.default
                .addObserver(self,
                             selector: #selector(textDidChange(notification:)),
                             name: UITextView.textDidChangeNotification,
                             object: textInput)
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc func textDidChange(notification: Notification) {
        checkUserInput()
    }
    
    func checkUserInput() {
        guard let textInput = textInput as? LimitLengthInput else {
            return
        }
        textInput.checkUserInputFor(limit: limit)
    }
}
